package cn.itsource.basic.service.impl;

import cn.itsource.basic.constants.BaseConstant;
import cn.itsource.basic.exception.BusinessException;
import cn.itsource.basic.service.IVerifyCodeService;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.SmsUtil;
import cn.itsource.basic.util.StrUtils;
import cn.itsource.basic.util.VerifyCodeUtils;
import cn.itsource.basic.vo.PhoneRegisterVo;
import cn.itsource.user.domain.User;
import cn.itsource.user.mapper.UserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;
    
    @Autowired
    private UserMapper userMapper;

    /*
    * 获取图形验证码的业务逻辑
    * 1.参数非空校验
    * 2.产生图形验证码
    * 3.将图形验证码保存到redis
    * 4.根据图形验证码产生base64字符串
    * */

    @Override
    public String image(String imageCodeKey) {
//        1.参数非空校验
        if (StringUtils.isBlank(imageCodeKey)){
            throw new BusinessException("获取图片验证码失败");
        }
//        2.产生图形验证码
        String imageCodeValue = StrUtils.getComplexRandomString(4);
//        3.将图形验证码保存到redis
        redisTemplate.opsForValue().set(imageCodeKey,imageCodeValue,3, TimeUnit.DAYS);
//        4.根据图形验证码产生base64字符串
        String base64Str = VerifyCodeUtils.VerifyCode(100, 40, imageCodeValue);
        return base64Str;
    }

    /*发送手机验证码sendSmsCode
     * 1.参数校验
     * 2.验证图形验证码是否正确
     * 3.查询手机号是否被注册过
     * 4.先从redis获取手机验证码
     *   4.1获取成功
     *       判断距离上次发送验证码的时间是否大于一分钟
     *           是   取出验证码,重置过期时间(3min),发送
     *           否   抛自定义异常("一分钟内不能重复获取验证码")
     *   4.2获取失败
     *       产生验证码,存到redis,发送验证码
     *
     * */
    @Override
    public void sendSmsCode(PhoneRegisterVo phoneRegisterVo) {
        String phone = phoneRegisterVo.getPhone();
        String imageCodeKey = phoneRegisterVo.getImageCodeKey();
        String imageCodeValue = phoneRegisterVo.getImageCodeValue();
//      1.参数校验
        if (StringUtils.isBlank(phone)
                ||StringUtils.isBlank(imageCodeKey)
                ||StringUtils.isBlank(imageCodeValue)
        ){
            throw new BusinessException("参数不能为空");
        }
//      2.验证图形验证码是否正确
        Object imageCodeValueInRedis = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeValueInRedis == null){
            throw new BusinessException("图形验证码过期");
        }
        if (!imageCodeValueInRedis.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("图形验证码输入错误");
        }
//      3.查询手机号是否被注册过
        User user = userMapper.loadByPhone(phone);
        if(user != null){
            throw new BusinessException("该手机号已注册");
        }
//      4.先从redis获取手机验证码
        Object smsCodeAndTime = redisTemplate.opsForValue().get(BaseConstant.VerifyConstants.USER_PHONE_REGISTER_CODE_PREFIX + phone);   //smsCodeAndTime--验证码:时间戳
        String smsCode;
//          4.1获取失败
        if (smsCodeAndTime == null){
            smsCode = StrUtils.getRandomString(6);
        }else {
//          4.2获取成功
//              判断距离上次发送验证码的时间是否大于一分钟
            Long currentTime = System.currentTimeMillis();//发送成功时的时间
            String[] smsCodeAndTimeArr = smsCodeAndTime.toString().split(":");
            smsCode = smsCodeAndTimeArr[0];//验证码
            Long oldTime = Long.valueOf(smsCodeAndTimeArr[1]);//从redis获取验证码时的时间
//                  否   抛自定义异常("一分钟内不能重复获取验证码")
            if (currentTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟后再次点击发送");
            }
        }
//              产生验证码,存到redis,发送验证码
        redisTemplate.opsForValue().set(BaseConstant.VerifyConstants.USER_PHONE_REGISTER_CODE_PREFIX + phone,smsCode+":"+System.currentTimeMillis(),3,TimeUnit.DAYS);
//        SmsUtil.sendSms(phone,"猫咪大王网站验证码为:"+smsCode+",请在三分钟内使用");
        System.out.println("猫咪大王网站验证码为:"+smsCode+",请在三分钟内使用");

    }
}
